package com.yetianhua.executor;

import com.yetianhua.pojo.Configuration;
import com.yetianhua.pojo.MappedStatement;
import com.yetianhua.sqlsession.BoundSql;
import com.yetianhua.util.GenericTokenParser;
import com.yetianhua.util.ParameterMapping;
import com.yetianhua.util.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author yetianhua
 * @className SimpleExecutor
 * @description TODO
 * @date 2021/6/2
 * @time 20:31
 */
public class SimpleExecutor implements Executor {

    public SimpleExecutor() {
    }

    public <T> List<T> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        // 1. 先获取connection
        Connection connection = configuration.getDataSource().getConnection();

        // 2. 根据sql生成BoundSql
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());

        String sql = boundSql.getSqlText();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        Class<?> resultTypeClass = Class.forName(mappedStatement.getResultType());
        List<ParameterMapping> parameterMapperings = boundSql.getParameterMapperings();
        // 设置参数
        for (int i = 0; i < parameterMapperings.size(); i++) {
            Class<?> parameterTypeClass = Class.forName(mappedStatement.getParamterType());
            Field field = parameterTypeClass.getDeclaredField(parameterMapperings.get(i).getContent());
            field.setAccessible(true);
            preparedStatement.setObject(i+1, field.get(params[0]));
        }

        // 设置返回数据
        ResultSet resultSet = preparedStatement.executeQuery();
        List<Object> result = new ArrayList<Object>();
        while(resultSet.next()){
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            Object obj = resultTypeClass.newInstance();
            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnName(i);
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(obj, resultSet.getObject(columnName));
            }
            result.add(obj);
        }

        return (List<T>) result;
    }

    public int update(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        // 1. 先获取connection
        Connection connection = configuration.getDataSource().getConnection();

        // 2. 根据sql生成BoundSql
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());

        String sql = boundSql.getSqlText();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        Class<?> resultTypeClass = Class.forName(mappedStatement.getResultType());
        List<ParameterMapping> parameterMapperings = boundSql.getParameterMapperings();
        // 设置参数
        for (int i = 0; i < parameterMapperings.size(); i++) {
            Class<?> parameterTypeClass = Class.forName(mappedStatement.getParamterType());
            Field field = parameterTypeClass.getDeclaredField(parameterMapperings.get(i).getContent());
            field.setAccessible(true);
            preparedStatement.setObject(i+1, field.get(params));
        }

        // 设置返回数据
        int executRow = preparedStatement.executeUpdate();

        return executRow;
    }

    public int updateOrDelete(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        // 1. 先获取connection
        Connection connection = configuration.getDataSource().getConnection();

        // 2. 根据sql生成BoundSql
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());

        String sql = boundSql.getSqlText();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        List<ParameterMapping> parameterMapperings = boundSql.getParameterMapperings();
        // 设置参数
        handlerParamter(parameterMapperings, mappedStatement.getParamterType(), preparedStatement, params);

        // 设置返回数据
        int executRow = preparedStatement.executeUpdate();

        return executRow;
    }

    private void handlerParamter(List<ParameterMapping> parameterMapperings, String paramterType, PreparedStatement preparedStatement, Object... params) throws Exception {
        for (int i = 0; i < parameterMapperings.size(); i++) {
            // 如果大于一个参数
            if(parameterMapperings.size() > 1) {
                Class<?> parameterTypeClass = Class.forName(paramterType);
                Field field = parameterTypeClass.getDeclaredField(parameterMapperings.get(i).getContent());
                field.setAccessible(true);
                preparedStatement.setObject(i + 1, field.get(params[0]));

            } else {
                // 如果参数只有一个
                preparedStatement.setObject(i + 1, params[0]);
            }
        }
    }

    private BoundSql getBoundSql(String sql) {
        ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler();
        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);

        BoundSql boundSql = new BoundSql();
        boundSql.setSqlText(parser.parse(sql));
        boundSql.setParameterMapperings(handler.getParameterMappings());
        return boundSql;
    }
}
